﻿package br.com.programatech.asfinance{
	/**
	* A classe Price é utilizada para cálculos. Não crie instâncias da Classe para a classe Price.
	*/
	public class Price{
		/**
		 * Calcula o Valor Presente(Present Value)
		 * 
		 * @param n Período
		 * @param i Valor da Taxa
		 * @param pmt Valor do pagamento
		 * @param fv Valor Futuro
		 * @param begin Indica quando o cáculo é iniciado a partir da primeira parcela
		 * 
		 * @return Valor Presente(Present Value)
		 * */
		public static function pv(n:Number,i:Number,pmt:Number,fv:Number, begin:Boolean = false):Number{
			i = i/100;
			var k:int = begin ? 0 : 1;
			var pv:Number;			
			if(i >0) pv = (pmt*(1+i*k)*(1-Math.pow(1+i,n))-i*fv)/(i*Math.pow(1+i,n));
			else pv = fv-(pmt*n);
			return(pv);
		}		
				
		/**
		 * Calcula o pagamento
		 * 
		 * @param n Período
		 * @param i Valor da Taxa
		 * @param pv Valor Presente
		 * @param fv Valor Futuro
		 * @param begin Indica quando o cáculo é iniciado a partir da primeira parcela
		 * 
		 * @return Retorna o Pagamento
		 * */
		public static function pmt(n:Number,i:Number,pv:Number,fv:Number, begin:Boolean = false):Number{
			i = i/100;
			var k:int = begin ? 0 : 1;
			var pmt:Number;			
			if(i >0) pmt = (i*(fv+pv*Math.pow(1+i,n))/((1+i*k)*(1-Math.pow(1+i,n))));
			else pmt = -(fv+pv)/n;
			return pmt;
		}
						
		/**
		 * Calcula o período
		 * 
		 * @param i Valor da Taxa
		 * @param pv Valor Presente
		 * @param pmt Valor Pagamento
		 * @param fv Valor Futuro
		 * @param begin Indica quando o cáculo é iniciado a partir da primeira parcela
		 * 
		 * @return Retorna o Período
		 * */	
		public static function n(i:Number,pv:Number,pmt:Number,fv:Number, begin:Boolean = false):Number{
			i = i/100;
			var k:int = begin ? 0 : 1;
			var n:Number ;
			if(i>0) n = Math.log((pmt*(1+i*k)-fv*i)/(pmt*(1+i*k)+pv*i))/Math.log(1+i);
			else {
				n = -(fv+pv)/pmt;
			}
			return n;
		}		
						
		/**
		 * Calcula o Valor Futuro
		 * 
		 * @param n Período
		 * @param i Valor da Taxa
		 * @param pv Valor Presente
		 * @param pmt Valor Pagamento
		 * @param begin Indica quando o cáculo é iniciado a partir da primeira parcela
		 * 
		 * @return Retorna o Período
		 * */	
		public static function fv(n:Number,i:Number,pv:Number,pmt:Number, begin:Boolean = false):Number{
			i = i/100;
			var k:int = begin ? 0 : 1;
			var fv:Number;
			if(i>0) fv = (pmt*(1+i*k)*(1-Math.pow(1+i,n))/i)-pv*Math.pow(1+i,n);			
			else fv = -(pv+pmt*n);
			return fv;
		}		
						
		/**
		 * Calcula a Taxa
		 * 
		 * @param n Período
		 * @param pv Valor Presente
		 * @param pmt Valor Pagamento
		 * @param fv Valor Futuro
		 * @param begin Indica quando o cáculo é iniciado a partir da primeira parcela
		 * 
		 * @return Retorna a Taxa
		 * */	
		public static function i(n:Number,pv:Number,pmt:Number,fv:Number,init:Number,begin:Boolean = false):Number{
			var i:Number = init/100;
			var count:int = 0;
			var f:Number;
			var fd:Number;
			var m:Number;
			do{
				count++;
				f = ifunction(n,i,pv,pmt,fv,begin);
				fd = idfunction(n,i,pv,pmt,fv,begin);
				m = f/fd;
				i = i-m;
				if((Math.abs(m)-0.000001) < 0){
					break;
				}
			}while(count < 1000);
			return i*100;
		}
				
		private static function ifunction(n:Number,i:Number,pv:Number,pmt:Number,fv:Number,begin:Boolean = false):Number{
			var k:int = begin ? 1 : 1+i;
			var f:Number = ((pmt*k/i) - ((Math.pow((1 + i),n))*(pv + ((pmt*k)/i))) - fv);
			return f;
		}
		private static function idfunction(n:Number,i:Number,pv:Number,pmt:Number,fv:Number,begin:Boolean = false):Number{
			var k:int = begin ? 1 : 1+i;
			var df:Number = -((k*pmt)/Math.pow(i,2))+((Math.pow((1+i),n)*k*pmt)/Math.pow(i,2))-(Math.pow((1+i),(-1+n))*n*(((k*pmt)/i)+pv));
			return df;
		}
	}	
}
